home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
vtkerma1.arc
/
MSFILE.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-02-13
|
40KB
|
1,570 lines
PAGE 59, 132
TITLE MSFILE -- Module to handle file I/O
; Update 20 Jan 86
IF1
%OUT >> Starting pass 1
ELSE
%OUT >> Starting pass 2
ENDIF
PUBLIC bufpnt, DTA, fcb, cpfcb, chrcnt, fixfcb, init, init1, gofil
PUBLIC outbuf, ptchr, gtchr, gtnfil, getfil, filbuf, encode, decode
PUBLIC nulref, nulr, decbuf, errpack, rptq, origr, rptct, rptval
PUBLIC clrfln, cxmsg, biterr, intmsg, Clear_percent_message
PUBLIC rppos, sppos, PerPr, KbPr, EOT_bells
PUBLIC kbpos, perpos, prtscr, Close_transfer_screen, AbFil
PUBLIC Say_aborted, Show_error, Show_warning, Show_status
PUBLIC Show_retries, Show_packets, Do_CXZ_mode_line
PUBLIC OFilSz, TFilSz, Write_to_standard_output
INCLUDE MsDefs.H
rptmin EQU 3 ; At least 3 of same char in a row
; equates for screen positioning
scrfln EQU 0316H ; Place for file name
scrkb EQU 0416H ; Place for Kbytes transferred
scrper EQU 0516H ; Place for percent transferred
Start_of_percent_line EQU 0500h ; Start of percent transferred line
scrst EQU 0616H ; Place for status
scrnp EQU 0816H ; Place for number of packets
scrnrt EQU 0916H ; Place for number of retries
screrr EQU 0A16H ; Place for error msgs
ScrWrn EQU 0B16H ; Where warnings are displayed
scrsp EQU 0C00H ; Place for send packet
scrrp EQU 0E00H ; Place for receive packet
DataS SEGMENT PUBLIC 'DataS'
extrn data:byte, flags:byte, trans:byte, pack:byte, hierr:byte
EVEN
temp1 DW ? ; Temporary storage
temp2 DW ?
chrcnt DW ? ; Number of chars in the file buffer
outpnt DW ? ; Position in packet
bufpnt DW ? ; Position in file buffer
fdtpnt DW ? ; Pointer to within our file
fcbptr DW ? ; Position in FCB
cbfptr DW ? ; Position in character buffer
filsiz DW 0 ; Double word for filesize (in bytes.)
DW 0
ofilsz DW 0 ; Original file size percent adjusted (/100)
tfilsz DW 0 ; Bytes transferred
DW 0
oldper DW 1234 ; old percentage
oldper2 DW 101 ; old percentage 2 (after computation)
oldkbt DW ? ; old KB transferred
bufhex DW 80H
File_handle DW 0 ; Handle of file we are currently working with
File_buffer_ptr DW 0 ; Pointer into file buffer
File_buffer_count DW 0 ; Number of bytes stored in buffer
; File_buffer DB 2048 DUP (?) ; Big buffer for reading and writing files
DTA DB 128 DUP (?) ; Used in wild-card searches
Ender DB Bell, Bell, '$' ; For end-of-transmission, if enabled
outlin DB cr,lf,cr,lf
db cr,lf,' File name:'
db cr,lf,' KBytes transferred: 0'
db cr,lf
db cr,lf
db cr,lf
db cr,lf,' Number of packets: 0'
db cr,lf,' Number of retries: 0'
db cr,lf,' Last error: None'
db cr,lf,' Last warning: None'
db '$'
NRD_Msg1 DB 'Please insert a formatted disk in the disk drive, or$'
NRD_Msg2 DB 'type control-C to ABORT. Press any key when ready.$'
WRP_Msg1 DB 'Please remove the write-protect tab from the diskette,$'
WRP_Msg2 DB 'or type control-C to ABORT. Press any key when ready.$'
NRD_Addr1 EQU (19*256)+5 ; Locations for messages
NRD_Addr2 EQU (20*256)+5
Abort_msg DB 'Aborted with ^C$'
ermes4 DB 'Unable to rename file$'
ermes4a DB 'Remote '
Program_name
DB ': Unable to rename file$'
erms10 DB 'Remote '
Program_name
DB ': Unable to receive data$'
erms11 DB 'Disk full$'
erms11a DB 'Remote '
Program_name
DB ': Disk full$'
ErMs12 DB 'Unable to create file$'
ErMs12a DB 'Remote '
Program_name
DB ': Unable to create file$'
erms17 DB 'Record length exceeds size of buffer$'
infms5 DB 'Renaming file to $'
InfMs7 DB 'File interrupt$'
InfMs8 DB 'File group interrupt$'
hibit DB 'Non-ASCII character in file$'
Q_mark DB '? $'
Percent_sign DB '% $'
crlf DB cr,lf,'$'
printer DB 0,'LPT1 '
spchar2 DB 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
DB 7BH,7DH,5FH,5EH,7EH,60H
spc2len EQU $-spchar2
Tmp DB ' ','$' ; One char string
next DB 0FFH ; No next character just yet
rptval DB 0 ; Repeated character
rptct DB 1 ; Number of times it's repeated
rptq DB drpt ; Repeat prefix
origr DB drpt ; Original repeat prefix
wrpmsg DB ? ; non-zero if we wrote percent message
permsg DB cr,' Percent transferred:$'
cxzhlp DB ' Ret=Retry ^X=Cancel file ^Z=Cancel group'
DB ' ^E=Protocol abort ^C=Full abort$'
asmsg DB ' as '
asmln EQU $-asmsg
filbuf DB 60H DUP(?) ; Character buffer
fcb DB fcbsiz DUP(?) ; Use as our FCB
cpfcb DB fcbsiz DUP(?) ; Save FCB in case of "*". [7]
decbuf DB dmasiz DUP(?) ; For decoding incoming data
DataS ENDS
Code SEGMENT PUBLIC
EXTRN SPack:NEAR, CmBlnk:NEAR, Locate:NEAR, Nout:NEAR
EXTRN PutMod:NEAR, PosCur:NEAR, ClearL:NEAR, FCBcpy:NEAR
EXTRN ClrMod:NEAR, Beep:NEAR, Get_Error:NEAR
ASSUME cs:Code, ds:DataS
; Display status of a file transfer
Show_status PROC
cmp Flags.RemFlg, 0 ; In remote mode?
jz SST_0 ; No
ret ; Quit quietly
SST_0: push dx ; Save ptr to message
mov dx, ScrSt ; Position for status messages
call PosCur ; Go there
call ClearL ; Clear out any existing message
pop dx ; Get back message
; jmp Write_to_standard_output ; Use standard routine to do this
Show_status ENDP
Write_to_standard_output PROC
mov di, dx ; Copy to di
cld ; Forwards
mov ax, ds ; Copy ds ...
mov es, ax ; ... to es
mov cx, 300 ; Scan lots of characters
mov al, '$' ; Want to find dollar sign
repne scasb ; Search for it
mov bx, di ; Find length of string
sub bx, dx ; Subtract ptr to start
mov di, dx ; Copy to di again
mov cx, 300 ; Scan lots of characters
sub al, al ; Look for a zero this time
repne scasb ; Search for it
mov cx, di ; Copy ending ptr to cx
sub cx, dx ; Subtract ptr to start
cmp cx, bx ; Use whichever length is LESS
jl WSO_1 ; Stick with cx (0 is closer than dollar sign)
mov cx, bx ; Use the other value (dollar sign is closer)
WSO_1: dec cx ; Drop by 1 for terminating value
mov ah, WRITEF2 ; Code to write to a file handle
mov bx, 1 ; Standard output
int Dos
ret
Write_to_standard_output ENDP
; Display number of retries
Show_retries PROC
cmp Flags.RemFlg, 0 ; In remote mode?
jz SRE_0 ; No
ret ; Quit quietly
SRE_0: mov dx, ScrNRt ; Position for number of retries
call PosCur ; Go there
mov ax, Pack.NumRtr ; Number of retries
call Nout ; Write the number
jmp ClearL ; Clear out rest of line
Show_retries ENDP
; Display number of packets
Show_packets PROC
cmp Flags.RemFlg, 0 ; In remote mode?
jz SPA_0 ; No
ret ; Quit quietly
SPA_0: mov dx, ScrNP ; Position for number of packets
call PosCur ; Go there
mov ax, Pack.NumPkt ; Number of packets
jmp Nout ; Write the number
Show_packets ENDP
; Say that file transfer has been aborted
Say_aborted PROC
mov dx, OFFSET Abort_msg ; The message
; jmp Show_error ; Use other routine to display it
Say_aborted ENDP
; Display an error message on a file transfer screen
Show_error PROC
call Beep ; Make a noise first
cmp Flags.RemFlg, 0 ; Are we in remote mode?
je SHE_0 ; No
push dx ; Save reg
mov dx, OFFSET Q_mark ; "? "
call Write_to_standard_output ; Output in binary mode
pop dx
jmp SHORT SHW_1 ; Join common code
SHE_0: push dx ; Save ptr to message
mov dx, ScrErr ; Position for error messages
call PosCur ; Go there
call ClearL ; Clear out any existing message
pop dx ; Get back message
jmp SHORT SHW_1 ; Use warning code, same thing
Show_warning:
cmp Flags.RemFlg, 0 ; Are we in remote mode?
je SHW_0 ; No
push dx ; Save reg
mov dx, OFFSET Percent_sign ; "% "
call Write_to_standard_output ; Output in binary mode
pop dx
jmp SHORT SHW_1 ; Join common code
SHW_0: push dx ; Save ptr to message
mov dx, ScrWrn ; Position for warning messages
call PosCur ; Go there
call ClearL ; Clear out any existing message
pop dx ; Get back message
SHW_1: call Write_to_standard_output ; Output in binary mode
cmp Flags.RemFlg, 0 ; Are we in remote mode?
je SHW_2 ; No
mov dx, OFFSET CrLf ; Ptr to CrLf
call Write_to_standard_output ; Output in binary mode
SHW_2: stc ; Force carry on in case it matters to anyone
ret ; Done here
Show_error ENDP
; Reassure user that we acknowledge his ^X/^Z
INTMSG PROC NEAR
cmp flags.xflg, 0 ; Writing to screen?
je INT_1 ; No, ok to show this warning
ret ; Do nothing
INT_1: mov dx, OFFSET InfMs7 ; File interrupted?
cmp flags.cxzflg, 'X'
je INT_2 ; Yes
mov dx, OFFSET InfMs8 ; File group interrupted
INT_2: jmp Show_warning ; Put it on screen
INTMSG ENDP
; Print err message that found a non-standard-Ascii char in the file
BITERR PROC NEAR
push bx
mov dx, OFFSET hibit ; Message about non-ASCII chars
call Show_warning ; Display it
pop bx
ret
BITERR ENDP
; Clear out message about interrupted file
CXMSG PROC NEAR
cmp flags.xflg,0 ; Writing to screen?
jne cxm0 ; Yes. Don't do anything
mov dx, ScrWrn
call poscur
call clearl
cxm0: ret
CXMSG ENDP
; Clear out the old filename on the screen
CLRFLN PROC
mov dx,scrfln
call poscur
jmp clearl ; Clear to end of line. [19a]
CLRFLN ENDP
; some random screen positioning functions
kbpos: mov dx,scrkb ; KBytes transferred
call poscur
jmp clearl
perpos: mov dx,scrper ; Percent transferred
call poscur
jmp clearl
sppos: mov dx,scrsp ; Send packet location
jmp poscur
rppos: mov dx,scrrp ; Receive packet location
jmp poscur
; Initialize buffers and clear line
INIT PROC
call Make_console_binary ; Set "console" into binary mode so
; "^C" isn't a problem
cmp Flags.RemFlg, 0 ; Remote mode?
jne Init1 ; Yes, no printing
call cmblnk
call locate
mov ah,prstr ; Put statistics headers on the screen
mov dx,offset outlin
int dos
call Do_CXZ_mode_line ; Use common code to do this
mov wrpmsg,0 ; haven't printed the messsage yet
; jmp init1
Init1: mov chrcnt, dmasiz ; Number of chars left
mov bufpnt, OFFSET DTA ; Addr for beginning
mov hierr, 0
ret
INIT ENDP
Do_CXZ_mode_line PROC
cmp Flags.RemFlg, 0 ; In remote mode?
jz DCM_0 ; No
ret ; Quit quietly
DCM_0: mov dx, OFFSET CXZHlp
jmp PutMod ; Write mode line
Do_CXZ_mode_line ENDP
; Common routine to close out any file transfer screen --
; erase the mode line and position the cursor in the lower
; left corner of the screen
Close_transfer_screen PROC
call Make_console_ASCII ; Set console back to ASCII mode
cmp Flags.RemFlg, 0 ; In remote mode?
jz CTS_0 ; No
ret ; Quit quietly
CTS_0: call ClrMod ; Erase the mode line
mov dx, 1600h ; Line above lower left corner
jmp PosCur ; Go there
Close_transfer_screen ENDP
; Switch console into and out of binary mode
Make_console_binary PROC
mov ax, 4400h ; IOCTL function 0, get device info
mov bx, 1 ; Standard output
int Dos ; Get current info
or dl, 20h ; Turn on the binary bit
sub dh, dh ; Clear high half
mov ax, 4401h ; IOCTL function 1, set device info
int Dos ; Set it up
ret
Make_console_binary ENDP
Make_console_ASCII PROC
mov ax, 4400h ; IOCTL function 0, get device info
mov bx, 1 ; Standard output
int Dos ; Get current info
and dl, NOT 20h ; Turn on the binary bit
sub dh, dh ; Clear high half
mov ax, 4401h ; IOCTL function 1, set device info
int Dos ; Set it up
ret
Make_console_ASCII ENDP
; Output the chars in a packet
; Called with AX = size of the data, BX = address of source
FILEIO PROC
ptchr: mov cx,ax
lea ax,outbuf ; Where to put data when buffer gets full
; jmp decode
; CX = Size of data, BX = Address of data, AX = Routine to call to
; dump data
decode: push si
push di
push es
push dx
push ax
mov ax,ds
mov es,ax
pop ax
mov si,bx ; Source of data
mov bx,ax ; Coroutine to call
mov di,bufpnt ; Destination of data
mov dh,0 ; assume no quote char
cmp trans.ebquot,'N' ; no quoting?
je decod1 ; yes, keep going
cmp trans.ebquot,'Y' ; or not doing it?
je decod1 ; yes, keep going
mov dh,trans.ebquot ; otherwise use quote char
decod1: mov rptct,0 ; Reset
mov rptval,0 ; Ditto
dec cx
jge dcod11 ; More data
jmp decod6 ; Else, we're through
dcod11: dec chrcnt ; Decrement number of chars in dta
jns decod2 ; Continue if space left
push cx
push dx
push bx
call bx ; Output it if full
jmp SHORT decod5 ; Error return if disk is full
nop
pop bx
pop dx
pop cx
mov di,bufpnt
decod2: cmp rptct,0 ; Doing a repeat?
je dcod20 ; No, so go get a character
mov ah,0
mov al,rptval ; Get the character we're repeating
jmp decod4 ; And write it out to the file
dcod20: lodsb ; Pick up a char
cmp rptq,0 ; Doing repeat quoting?
je dcod21 ; Nope, skip this part
cmp al,rptq ; Did we pick up the repeat quote char?
jne dcod21 ; No, continue processing it
lodsb ; Get the size
dec cx ; Modify buffer count
sub al,20H ; Was made printable
mov rptct,al ; Remember how many repetitions
lodsb ; Get the char to repeat
dec cx ; Modify buffer count
dcod21: mov ah,00H ; Assume no 8-bit quote char. [21b start]
cmp al,dh ; This the 8-bit quot char?
jne decod3
lodsb ; Get the real character
dec cx ; Decrement # chars in packet
mov ah,80H ; Turn on 8-bit quot char flag. [21b end]
decod3: cmp al,trans.squote ; Is it the quote char? [21b] [21c]
jne decod4 ; If not proceed
lodsb ; Get the quoted character
dec cx ; Decrement # of chars in packet
or ah,al ; save parity (combine with prefix)
and ah,80h ; only parity
and al,7FH ; Turn off the parity bit
cmp al,trans.squote ; Is it the quote char? [21c]
je decod4 ; If so just go write it out
cmp al,dh ; This the 8-bit quot char?
je decod4 ; If so, just go write it out
cmp al,rptq ; Is is the repeat quote character?
je decod4 ; If so, just write it out
add al,40H ; Make it a control char again
and al,7FH ; Modulo 128
decod4: or al,ah ; or in parity
stosb ; store the character
dec rptct ; Repeat counter
cmp rptct,0 ; Write out char again?
jg dcod41
jmp decod1 ; No, get next char
dcod41: mov rptval,al ; Save the char
jmp dcod11 ; and loop to next char
decod5: pop bx
pop dx ; dx is pushed twice (really)
pop cx
pop dx
pop es
pop di
pop si
ret
decod6: mov bufpnt,di
pop dx
pop es
pop di
pop si
jmp rskp ; Return successfully if done
; output the buffer, reset bufpnt and chrcnt
outbuf: cmp flags.xflg,1 ; Writing to screen? [21c]
je outbf2 ; Yes, handle specially. [21c]
push bx
mov ah,writef ; The write code
mov dx,offset fcb
int dos ; Write the record
pop bx
cmp al,0 ; Successful
jz outbf1
push ax ; Remember the return code. [20d]
call abfil ; Fix things up before aborting. [20d]
pop ax ; Retrive return code. [20d]
cmp al,01
je outbf0
mov dx, OFFSET erms17 ; Record length exceeds dta
call Show_error
mov bx, OFFSET erms10 ; Text of message to send
jmp errpack ; Send an error packet, ret from there
outbf0: mov dx, OFFSET erms11 ; Disk full error
call Show_error
mov bx, OFFSET erms11a ; Text of message to send
jmp errpack ; Send an error packet
outbf1: add tfilsz+2,80H ; Say 128 more characters received
adc tfilsz,0
call kbpr ; Print the kilobytes received
call perpr ; Print the percent ('?' for now)
outb11: mov bufpnt,offset DTA ; Addr for beginning
mov chrcnt,dmasiz-1 ; Buffer size
jmp rskp
outbf2: mov cx,dmasiz-1 ; Number of chars to write. [21c]
sub cx,chrcnt ; minus # of unused in buffer
mov di,offset DTA ; Where they are. [21c]
call prtscr ; Output buffer to screen. [21c]
jmp outb11 ; Reset counter & pointer. [21c]
; Tidy up before aborting. [20d]
ABFIL PROC
mov ah,closf ; Close the file
mov dx,offset fcb
int dos
cmp flags.abfflg,1 ; Delete what got across or keep it?
jne abfil0 ; Nope, keep it
mov ah,delf ; Delete it
mov dx,offset fcb
int dos
abfil0: ret
ABFIL ENDP
; General routine for sending an error packet. Register BX should
; point to the text of the message being sent in the packet. [20f]
ERRPACK PROC
mov di,offset data ; Where to put the message
mov al,0
errp1: mov ah,[bx]
cmp ah,'$' ; At end of message?
je errp2
inc al ; Remember number of chars in msg
mov [di],ah
inc bx
inc di
jmp errp1
errp2: mov ah,0
mov pack.argbk1,ax
mov ah,'E' ; And send an error packet
call spack
ret ; Return if succeed or fail
nop
nop
ret
ERRPACK ENDP
; Get the chars from the file
gtchr: cmp flags.filflg,0 ; Is there anything in the DMA?
jz gtchr0 ; Yup, proceed
mov ah,rptq
mov origr,ah ; Save repeat prefix here
mov rptct,1 ; Number of times char is repeated
mov rptval,0 ; Value of repeated char
call inbuf
jmp gtchr1 ; No more chars, go return EOF
nop ; Make three bytes long
gtchr0: lea bx,inbuf
jmp encode
gtchr1: mov ax,0ffffh
ret
; encode - writes data portion of kermit packet into filbuf
; expects BX to contain the address of a routine to refill the buffer,
; chrcnt to be the # of chars in the buffer, trans.maxdat to contain
; the maximum size of the data packet, bufpnt to contain a pointer to
; the source of the characters
; Returns: AX/ the number of characters actually written to the buffer
encode: mov cl,trans.maxdat ; Maximum packet size. [21b]
mov ch,0
mov di,offset filbuf ; Where to put the data
mov si,bufpnt ; pointer into source buffer
mov dl,trans.rquote ; send quote char
mov dh,0 ; assume no 8-bit quoting
cmp trans.ebquot,'N' ; not doing 8-bit quoting
je encod1
cmp trans.ebquot,'Y' ; or can but won't?
je encod1
mov dh,0ffh ; remember we have to do it
encod1: dec cx ; Decrement output buffer counter
jge encod2 ; Go on if there is more than one left
sub di,offset filbuf
mov ax,di
mov bufpnt,si ; update pointer into DMA
jmp rskp
encod2: dec chrcnt ; any data in buffer?
jge encod3 ; yes, skip over buffer refill
call bx ; Get another buffer full
jmp encod8
mov si,bufpnt ; update position in DMA
cmp chrcnt,0 ; no characters returned?
jne encod3 ; Got some, keep going
jmp encod8 ; none, assume eof
encod3: lodsb
cmp rptq,0 ; Are we doing repeat prefixing?
je encd3x ; Nope, skip next part
cmp chrcnt,0 ; Are we on the last character?
jle encd31 ; Yes, so there's no next character
cmp rptct,94 ; Max number that we can put in a byte
je encd31 ; Then that's it
mov ah,[si] ; Get the next character
cmp al,ah ; Is current char == next char?
jne encd31
inc rptct ; Number of times char appears
mov rptval,al ; Remember the character
inc cx ; Repeats don't take up so much buffer space
jmp encod1 ; Keep checking for more
encd31: cmp rptct,1 ; Were previous characters repeats?
je encd3x ; No, so just add this char
cmp rptct,rptmin ; Are we within bounds for repeat prefixing?
jge encd32 ; Yes, use repeat prefixing
mov al,rptct
mov ah,0
sub si,ax ; Not enough characters to warrant it
mov rptval,0 ; Clear out this value
inc cx ; Adjust output buffer pointer
mov al,rptq
mov origr,al ; Save original repeat prefix
mov rptq,0 ; Pretend we're not doing the prefixing
mov al,rptct
mov ah,0
add chrcnt,ax ; Adjust input buffer pointer
jmp encod1 ; Reprocess those characters
encd32: push ax ; Do repeat prefixing - save data
mov al,rptq ; Add repeat prefix char
stosb
dec cx ; Account for it in buffer size
mov al,rptct ; Get the repeat count
add al,20H ; Make it printable
stosb ; Add to buffer
dec cx
pop ax ; Get back the actual character
mov rptct,1 ; Reset repeat count
mov rptval,0 ; And this
%OUT >> About half way through source file
encd3x: cmp dh,0 ; are we doing 8-bit quoting?
je encod4 ; no, forget this
test al,80h ; parity on?
je encod4 ; no, don't bother with this
and al,7fh ; turn off parity
push ax ; save original char for a bit
dec cx ; decrement # of chars left
mov al,trans.ebquot ; get quote char
stosb ; save in buffer
pop ax ; restore character
encod4: mov ah,al ; save character
and ah,80h ; only parity
and al,7fh ; turn off parity in character
cmp al,' ' ; Compare to a space
jl encod5 ; If less then its a control char
cmp al,del ; Is the char a delete?
jz encod5 ; Go quote it
cmp al,dl ; Is it the quote char?
je encod6 ; Yes - go add it. [21b start]
cmp dh,0 ; are we doing 8-bit quoting?
je encd41 ; no, don't translate it
cmp al,trans.ebquot ; Is it the 8-bit quote char?
je encod6 ; Yes, just output with quote
encd41: cmp origr,0 ; Doing repeat prefixing?
je encod7 ; No, don't check for quote char
cmp al,origr ; Is this the repeat quote character
je encod6 ; Yes, then quote it
jmp short encod7 ; else don't quote it
encod5: add al,40h ; control char, uncontrollify
and al,7fh
encod6: push ax ; save the char
dec cx
mov al,dl
stosb
pop ax
encod7: or al,ah ; put parity back
stosb
cmp rptct,1 ; One occurence of this char?
jne encd7x
mov al,origr
mov rptq,al ; Restore repeat quote char
jmp encod1 ; Yes, so loop around for some more
encd7x: dec rptct ; Add another entry of this char
jmp encod1 ; With quoting and all
encod8: sub di,offset filbuf
or di,di
je encod9 ; Nope
mov ax,di
jmp rskp
encod9: mov ax,0FFFFH ; Get a minus one
ret
inbuf: mov ah,flags.eoflag ; Have we reached the end?
cmp ah,0
jz inbuf0
ret ; Return if set
inbuf0: push si
push di
push dx
push bx
push cx
mov bx,offset DTA ; Set the r/w buffer pointer
mov bufpnt,bx
mov ah,readf ; Read a record
mov dx,offset fcb
int dos
mov cx,filsiz
cmp cx,0 ; Check for 128 chars or less left
jne inbuf1 ; Still have data left
mov ax,ds
mov es,ax
mov si,offset filsiz+2
mov di,offset bufhex
cmps filsiz+2,es:bufhex
ja inbuf1 ; More than 128 chars
mov flags.eoflag,0FFH ; Set End-of-file
mov cx,filsiz+2
cmp flags.filflg,0 ; Ever used DMA? [25]
jnz inbf01
dec cx ; Account for DEC in caller routine
inbf01: mov chrcnt,cx ; Return proper number of chars
mov flags.filflg,0 ; Buffer not empty
pop cx
pop bx
pop dx
pop di
pop si
jmp rskp
inbuf1: sub filsiz+2,80H ; Sent another 128 chars
sbb filsiz,0 ; Account for the doubleword
add tfilsz+2,80H ; Book keeping for the same
adc tfilsz,0
push ax
call kbpr ; Print the kilobytes sent
call perpr ; Print the percent sent
pop ax
mov al,80H ; Use as counter for number of chars read
pop cx
pop bx
pop dx
pop di
pop si
cmp flags.filflg,0 ; Ever used DMA?
jnz inbf21 ; Nope, then don't change count
dec al ; Fix boundary error
inbf21: mov ah,0 ; Zero the flag (buffer not empty)
mov chrcnt,ax ; Number of chars read from file
mov flags.filflg,0 ; Buffer not empty
jmp rskp
nulref: mov chrcnt,0 ; No data to return
jmp rskp
nulr: ret
; Print the number of Kilobytes transferred
kbpr: cmp flags.remflg,0 ; remote mode?
jne kbpr1 ; yes, no printing
mov ax,tfilsz+2
and ax,not (1111111111B) ; exclude low-order ten bits
or ax,tfilsz ; get size words
cmp ax,oldkbt ; is it the same?
je kbpr1 ; yes, no printing
mov oldkbt,ax
mov ax,tfilsz+2 ; Get low order word
mov cl, 10 ; Set up CL for shift count
shr ax,cl ; Divide by 1024
mov bx,tfilsz ; Get high order word
mov cl, 6 ; Set up CL for shift count
shl bx,cl ; Move over to OR into AX
or ax,bx
push ax
call kbpos ; Postion the cursor
pop ax
call nout ; Print the number of KBytes transferred
kbpr1: ret
; Print the percent transferred
PerPr: cmp Flags.RemFlg, 0 ; Remote mode?
jne PPR_3 ; Yes, no printing
cmp OFilSz, 0 ; Don't divide by zero
je PPR_3 ; If not proceed
mov ax, tfilsz ; Build silly hash value
or ax, tfilsz+2
cmp ax, oldper ; Same as it was before?
je PPR_3 ; Yes, don't bother printing
mov oldper, ax ; Remember for next time
cmp wrpmsg, 0 ; Did we write the percentage message?
jne PPR_1 ; Yes, skip this part
call PerPos ; position cursor
mov ah, PrStr
mov dx, OFFSET PerMsg
int Dos ; Write out message
mov WrPMsg, 1 ; Init flag so we don't do it again
PPR_1: mov dx, TFilSz ; Get the high order word
mov ax, TFilSz+2 ; Get the low order word
div OFilSz ; Div by percent adjusted original file size
cmp ax, 100 ; > 100% ?
jle PPR_2 ; No, accept it
mov ax, 100 ; Else just use 100
PPR_2: cmp ax, OldPer2 ; Same percent as last time?
je PPR_3 ; Yes, don't flash cursor over same data
mov OldPer2, ax ; Save for next time here
push ax ; Save reg
call PerPos ; Position the cursor
pop ax
call Nout
mov ah, ConOut ; Print a character
mov dl, '%' ; Load a percent sign
int Dos
PPR_3: ret
Clear_percent_message:
mov WrpMsg, 0 ; Forget this was ever here
cmp Flags.RemFlg, 0 ; In remote mode?
jne CPM_0 ; Yes, skip this
cmp Flags.XFlg, 0 ; Writing to screen?
jne CPM_0 ; Yes, skip this
mov dx, Start_of_percent_line ; Where to go
call PosCur ; Go there
call ClearL ; Wipe the line
CPM_0: ret ; Done here
EOT_bells:
cmp Flags.BelFlg, 0 ; Bell desired?
je CEB_0 ; No
mov ah, PrStr ; Code to type a string
mov dx, OFFSET Ender ; ^G^G
int Dos ; Type it
CEB_0: ret ; Done here
getfil: mov ah,0FFH
mov flags.filflg,ah ; Nothing in the DMA
sub ax, ax
mov flags.eoflag,ah ; Not the end of file
mov bx,offset fcb+0CH
mov [bx],ax ; Zero the current block number
mov bx,offset fcb+0EH
mov [bx],ax ; Ditto for Lrecl
mov bx,offset fcb+20H
mov [bx],ah ; Zero the current record (of block)
inc bx
mov [bx],ax ; Same for record (of file)
mov bx,offset fcb+23H
mov [bx],ax
mov ah,openf ; Open the file
mov dx,offset fcb
int dos
mov dx,word ptr fcb+18 ; get file size (hi order word)
mov filsiz,dx
mov ax,word ptr fcb+16 ; lo order word
mov filsiz+2,ax
mov bx, 100 ; Get a 100
div bx ; Divide by it to convert for percentage
mov ofilsz,ax
mov tfilsz,0 ; Set bytes sent to zero
mov tfilsz+2,0
mov oldkbt,-1
mov oldper,-1
cmp filsiz,0 ; Null file?
jne getfl0 ; Nope
cmp filsiz+2,0 ; Null file?
jne getfl0 ; Nope
mov flags.eoflag,0FFH ; Set EOF
getfl0: jmp rskp
gtnfil: cmp flags.cxzflg,'Z' ; Did we have a ^Z? [20b]
je gtn5 ; If yes, we're done sending files. [20b]
cmp flags.wldflg,0 ; Was there a "*"? [7 start]
je gtn5 ; Nope
mov bx,offset cpfcb ; Get FCB from last check for file.
mov di,offset fcb ; Copy to FCB
mov cl,37 ; Size of FCB
call fcbcpy
gtn2: mov ah,snext
mov dx,offset fcb ; More files?
int dos
cmp al,0FFH
je gtn5
mov bx,offset fcb
mov di,offset cpfcb
mov cl,37
call fcbcpy ; Copy from FCB
mov di,offset fcb+1 ; Get name of next file to send
mov bx,offset DTA+1
mov cl,11
call fcbcpy
call getfil ; Initialize
jmp r
jmp rskp
gtn5: mov flags.wldflg,0 ; Reset wild card flag
ret ; [7 end]
; Get the file name (including host to micro translation)
PUBLIC GoFlx, GoFil0, GoFil7, GoFil1
gofil: cmp flags.xflg,1 ; Remote command? [21c]
jne goflx ; No.... [21c]
jmp gofla ; Yes so skip this stuff. [21c]
goflx: cmp flags.nmoflg,1 ; Overriding name from other side? [21a]
jne gofil0 ; No - get the filename. [21a]
; Have to set up TEMP2 in case file must be renamed
mov cx, 9 ; Start here
cmp FCB + 8, ' ' ; Blank here?
jne goflx_0 ; No
mov cx, 7
cmp FCB + 7, ' ' ; Blank here?
jne goflx_0 ; No
dec cx
cmp FCB + 6, ' ' ; Blank here?
jne goflx_0 ; No
dec cx
cmp FCB + 5, ' ' ; Blank here?
jne goflx_0 ; No
dec cx
cmp FCB + 4, ' ' ; Blank here?
jne goflx_0 ; No
dec cx
cmp FCB + 3, ' ' ; Blank here?
jne goflx_0 ; No
dec cx
cmp FCB + 2, ' ' ; Blank here?
jne goflx_0 ; No
goflx_0:
mov temp2, cx ; Save for possible rename
jmp gofil7 ; Ignore packet contents
gofil0: mov bx,offset data ; Get the address of the file name. [21a]
mov fdtpnt,bx ; Store the address
mov bx,offset fcb+1 ; Address of the FCB
mov fcbptr,bx ; Save it
sub ax, ax
mov temp1,ax ; Initialize the char count
mov temp2,ax
cmp flags.droflg,1 ; Default drive? [21a]
je gofil1 ; No - don't blank out value in FCB. [21a]
mov si,offset fcb
mov [si],ah ; Set the drive to default to current
gofil1: mov ch,' ' ; Moved the label. [21a]
mov [bx],ch ; Blank the FCB
inc bx
inc ah
cmp ah,0BH ; Twelve?
jl gofil1
gofil2: mov bx,fdtpnt ; Get the NAME field
mov ah,[bx]
inc bx
mov fdtpnt,bx
cmp ah,'.' ; Separator?
jne gofil3
mov bx,offset fcb+9
mov fcbptr,bx
mov ax,temp1
mov temp2,ax
mov temp1,9
jmp gofil6
gofil3: cmp ah,0 ; Trailing null?
jz gofil7 ; Then we're done
call verlet ; Verify that the char is legal
mov bx,fcbptr
mov [bx],ah
inc bx
mov fcbptr,bx
mov ax,temp1 ; Get the char count
inc ax
mov temp1,ax
cmp ax,8H ; Are we finished with this field?
jl gofil2
gofil4: mov temp2,ax
mov bx,fdtpnt
mov ah,[bx]
inc bx
mov fdtpnt,bx
cmp ah,0
jz gofil7
cmp ah,'.' ; Is this the terminator?
jne gofil4 ; Go until we find it
gofil6: mov bx,fdtpnt ; Get the TYPE field
mov ah,[bx]
inc bx
mov fdtpnt,bx
cmp ah,0 ; Trailing null?
jz gofil7 ; Then we're done
call verlet ; Verify that the char is legal
mov bx,fcbptr
mov [bx],ah
inc bx
mov fcbptr,bx
inc temp1 ; Increment char count
cmp temp1,0CH ; Are we finished with this field?
jl gofil6
gofil7: cmp flags.remflg,0 ; remote mode?
jne gofil7a ; yes, don't print it
call prtfn ; Print the file name. [21a]
gofil7a:cmp flags.destflg,0 ; Writing to the printer?
jne gf7y
push es
mov ax,ds
mov es,ax ; Set this up
mov cx,11
mov si,offset printer
mov di,offset fcb
repne movsb ; Change name in FCB to be printer
pop es
jmp gofil9
gf7y: mov ah,flags.flwflg ; Is file warning on?
cmp ah,0
jnz gf7x
jmp gofil9 ; If not, just proceed
gf7x:
gf7xa: mov ah,openf ; See if the file exists
mov dx,offset fcb
int dos
cmp al,0FFH ; Does it exist?
jnz gf8x ; File exists, have to rename the incoming one
call Check_for_Not_Ready ; Had an error, check for Drive Not Ready
jnc gf7xa ; Drive Not Ready, user wants to try again
jmp gofil9 ; Go create the file
gf8x: mov dx, OFFSET InfMs5 ; Renaming file to ...
call Show_warning
mov ax,temp2 ; Get the number of chars in the file name
cmp ax,0
jne gofil8
mov ax,temp1
mov temp2,ax
gofil8: mov ch,0
mov cl,al
mov al,0 ; Says if first field is full
cmp cl,9H ; Is the first field full?
jne gofl81
mov al,0FFH ; Set a flag saying so
dec cl
gofl81: mov bx,offset fcb ; Get the FCB
add bx,cx ; Add in the character number
mov ah,'&'
mov [bx],ah ; Replace the char with an ampersand
push ax
push bx
mov ah,openf ; See if the file exists
mov dx,offset fcb
int dos
pop bx
cmp al,0FFH ; Does it exist?
pop ax
jz gofl89 ; If not create it
cmp al,0 ; Get the flag
jz gofl83
dec cl ; Decrement the number of chars
cmp cl,0
jz gofl88 ; If no more, die
jmp gofl81
gofl83: inc cl ; Increment the number of chars
cmp cl,9H ; Are we to the end?
jl gofl81 ; If not try again ; else fail
gofl88: mov dx, OFFSET ErMes4 ; Unable to rename file
call Show_error
mov bx, OFFSET ErMes4a ; Unable to rename file
jmp errpack ; Send error packet before abort. [20f]
gofl89: cmp Flags.RemFlg, 0 ; Remote mode?
jne gofil9 ; Yes, don't have to print file name
; Type out the selected file name
mov cx, 8 ; Maximum number of chars to type
mov dx, OFFSET Fcb+1 ; Addr of the file name part
call Type_without_trailing_blanks ; Type the first part
mov Tmp, '.' ; Load a period
mov ah, PrStr ; Code to type string
mov dx, OFFSET Tmp ; The "string"
int Dos ; Type the period
mov cx, 3 ; Maximum number of chars to type
mov dx, OFFSET Fcb+9 ; Addr of the file type part
call Type_without_trailing_blanks ; Type the second part part
gofil9: mov ah,delf ; Delete the file if it exists
mov dx,offset fcb
int dos
sub ax, ax
mov si,offset fcb+0CH
mov [si],ax ; Zero current block
mov si,offset fcb+0EH
mov [si],ax ; Same for Lrecl
mov si,offset fcb+20H
mov [si],ah ; Zero the current record (within block)
inc si
mov [si],ax ; Zero record (within file)
mov si,offset fcb+23H
mov [si],ax
mov ofilsz,0 ; File size unknown
mov tfilsz,0 ; Set bytes received to zero
mov tfilsz+2,0
mov oldkbt,-1
mov oldper,-1
mov ah,makef ; Now create it
mov dx,offset fcb
int dos
cmp al,0FFH ; Is the disk full?
je gf9x
jmp rskp
gf9x: call Check_for_Write_Protect ; We had an error, see if it was WP
jc gf9x0 ; Not that type, or ABORT
jmp gf7x ; Write Protect, user wants to try again, go
; all the way back to the Drive Ready check
gf9x0: mov dx, OFFSET ErMs12 ; Unable to create file
call Show_error
mov bx, OFFSET ErMs12a ; Unable to create file
jmp errpack ; Send an error packet
gofla: cmp pack.argbk1,0 ; Any data in "X" packet? [21c start]
je gofla1 ; Nothing to print
mov ah,prstr
mov dx,offset crlf
int dos
mov di,offset data ; Where data is
mov cx,pack.argbk1 ; How much data we have
call prtscr ; Print it on the screen
gofla1: mov ah,prstr
mov dx,offset crlf
int dos
jmp rskp ; And done. [21c end]
FILEIO ENDP
; Routines to put friendly messages on the screen in special cases of
; understandable disk errors -- Drive Not Ready and Write Protect Error
Tmsg MACRO Message
mov dx, OFFSET Message
mov ah, PrStr
int Dos
ENDM
GoMsg MACRO Prefix,Number
mov dx, NRD_Addr&Number
call PosCur
Tmsg Prefix&_Msg&Number
ENDM
PUBLIC Check_for_Not_Ready, Check_for_Write_Protect
Check_for_Not_Ready PROC
call Get_Error ; See what the error code was
cmp ax, 2 ; Code for Drive Not Ready
jne CCC_Abort ; Not what we got, give up
GoMsg NRD,1
GoMsg NRD,2
jmp SHORT Check_common_code
Check_for_Not_Ready ENDP
Check_for_Write_Protect PROC
call Get_Error ; See what the error code was
cmp ax, 0 ; Code for Write Protect error
jne CCC_Abort ; Not what we got, give up
GoMsg WRP,1
GoMsg WRP,2
Check_common_code:
call Beep ; Go make a noise
mov ah, ConInQ ; Quiet console input
int Dos ; Wait until user hits a key
call Erase_error_message ; Get rid of the message
cmp al, 3 ; Control-C?
je CCC_Abort ; Yes, don't accept the file
clc ; Clear carry for no error
ret ; Return ready for retry
CCC_Abort:
stc ; Set carry for error
ret ; Return error
Check_for_Write_Protect ENDP
PUBLIC Erase_error_message
Erase_error_message PROC
Clear_it MACRO Address
mov dx, Address ;; Position
call PosCur ;; Go there
call ClearL ;; Clear out any existing message
ENDM
push ax ; Save reg
Clear_it NRD_Addr1 ; Clear each line
Clear_it NRD_Addr2
pop ax ; Restore reg
ret
Erase_error_message ENDP
; Call with ...
; cx/ maximum number of chars to type
; dx/ OFFSET within ds: of string to type
PUBLIC Type_without_trailing_blanks
Type_without_trailing_blanks PROC
LP_1: mov bx, cx ; Copy to bx
add bx, dx ; Add in OFFSET to string
cmp BYTE PTR -1[bx], ' ' ; Is this a space?
jne Got_one
loop LP_1
ret ; Nothing but blanks, print nothing
Got_one:
cld ; Forwards
mov ah, PrStr ; Doing this repeatedly
mov si, dx ; Start at start of string
mov dx, OFFSET Tmp ; Point at Tmp string
LP_2: lodsb ; Pick up this byte
mov Tmp, al ; Copy to Tmp
int Dos ; Type the next byte
loop LP_2 ; Go do another one
ret ; Done here
Type_without_trailing_blanks ENDP
; Passed char of incoming filename in AH. Verify that it is legal
; and if not change it to an "X"
verlet: cmp ah,'0'
jl ver2 ; See if it's a legal weird char
cmp ah,'z'+1
jns ver2
cmp ah,'9'
jle ver1 ; It's between 0-9 so it's OK
cmp ah,'A'
jl ver2 ; Coud be a weird char
cmp ah,'Z'
jle ver1 ; It's A-Z so it's OK
cmp ah,'a'
jl ver2
and ah,137O ; It's a-z, capitalize
ver1: ret
ver2: push es
mov cx,ds
mov es,cx ; Scan uses ES register
mov di,offset spchar2
mov cx,spc2len
mov al,ah ; Char is in al
repnz scasb ; Search string for input char
pop es
mov ah,al ; Return it in AH
cmp cx,0 ; Was it there?
jnz ver1 ; Yes, return it
mov ah,'X' ; If illegal, replace with "X"
mov flags.nmoflg,1
ret
; Print incoming filename(s). [21a]
PRTFN PROC
call clrfln ; Position cursor & blank out the line
mov di, OFFSET data ; Where to put the name
cmp flags.nmoflg, 0 ; Is filename in packet?
je prtfn1 ; no, keep going
add di, pack.argbk1 ; bump by length of remote name
mov si, OFFSET asmsg ; something to put after it
mov cx, asmln ; length of it
rep movsb ; add this to the buffer
prtfn1: cmp flags.droflg,0 ; Drive specified?
je prtfn2 ; No
mov al, BYTE PTR FCB ; Pick up drive spec from FCB
add al, '@' ; Make it readable
stosb ; Add to buffer
mov al, ":" ; And a colon
stosb ; Add it also
prtfn2: mov cx,8 ; At most 8 letters in file name
mov si, OFFSET FCB + 1 ; This is the source now
prtfn3: lodsb ; get a letter
cmp al,' ' ; Done with name?
je prtfn4 ; yes, continue
stosb ; else store
loop prtfn3 ; and loop thru rest
prtfn4: mov si,offset fcb+9 ; Point to file type
cmp byte ptr [si],' ' ; is there a type?
je prtfn5 ; Nope so we're done
mov al,'.' ; Add the dot
stosb
mov cx,3 ; At most 3 letters in file type
rep movsb ; copy type (incl trailing spaces)
prtfn5: mov ah, WRITEF2 ; Code to write to a file handle
mov bx, 1 ; Standard output
mov cx, di ; Copy ending ptr to cx
sub cx, OFFSET Data ; Get length of data
mov dx, OFFSET Data ; Ptr to data
int Dos ; Type it to standard output
;tm mov flags.droflg,0 ; Reset flag once have the full name
mov flags.nmoflg,0
ret
PRTFN ENDP
; Print data onto the screen.
;
; Routine expects: DI = Start of buffer we are to print
; CX = Number of characters to print. [21c]
PRTSCR PROC
mov ah, WRITEF2 ; DOS 2.0 file handle write
mov bx, 1 ; File handle 1 is standard output
mov dx, di ; Copy buffer ptr to dx
int Dos ; cx was already set up, just type the string
ret ; That's it
PRTSCR ENDP
FIXFCB PROC
push ax ; Don't forget this. [22]
mov bx,offset fcb+18
mov di,offset filsiz
mov ax,[bx]
mov [di],ax
mov bx,offset fcb+16
mov ax,[bx]
mov 2[di],ax
pop ax ; Get number of chars in last buffer full. [22]
sub filsiz+2,ax ; Get real file size
sbb filsiz,0
mov bx,offset fcb+18
mov di,offset filsiz
mov ax,[di]
mov [bx],ax
mov bx,offset fcb+16
mov ax,2[di]
mov [bx],ax
ret
FIXFCB ENDP
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr
RSKP PROC NEAR
pop bp
add bp,3
push bp
; ret
RSKP ENDP
; Jumping here is the same as a ret
R PROC NEAR
ret
R ENDP
Code ENDS
END